package com.aiks.dsyncpluginspringbootautoconfigure.plugin;


import cn.hutool.core.util.ReflectUtil;
import com.aiks.dsyncpluginspringbootautoconfigure.BusinessException;
import com.aiks.dsyncpluginspringbootautoconfigure.pojo.ModuleConfigEntity;
import com.aiks.dsyncpluginspringbootautoconfigure.pojo.OrgFieldEntity;
import lombok.SneakyThrows;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * AbstractPorpertiesPlugin.
 *
 * @author <a href="mailto:yuanz@yxt.com">yuanz</a>
 * @date 2022-06-27 17:19
 * @since 1.0.0
 **/
public abstract class AbstractPorpertiesPlugin<T> extends AbstractPlugin<T> {
    
    /**
     * execute.
     *
     * @param moduleConfig moduleConfig
     * @param saasDatas    saasDatas
     * @param clientDatas  clientDatas
     */
    @Override
    public void execute(final ModuleConfigEntity moduleConfig, final List<T> saasDatas, final List<Object> clientDatas) {
        attributeMapping(moduleConfig, saasDatas, clientDatas);
        if (null != getNext()) {
            getNext().execute(moduleConfig, saasDatas, clientDatas);
        }
    }
    
    /**
     * attributeMapping.
     *
     * @param moduleConfig moduleConfig
     * @param saasDatas    saasDatas
     * @param clientDatas  clientDatas
     */
    protected void attributeMapping(final ModuleConfigEntity moduleConfig, final List<T> saasDatas,
                                    final List<Object> clientDatas) {
        if (isExecute(moduleConfig, getPluginEnum())) {
            clientDatas.stream().forEach(obj -> saasDatas.add(buildDTO(obj, moduleConfig.getOrgFieldEntities())));
        } else {
            throw new BusinessException("not config PorpertiesPlugin");
        }
    }
    
    /**
     * buildDTO.
     *
     * @param obj              obj
     * @param orgFieldEntities orgFieldEntities
     * @return T
     */
    protected T buildDTO(final Object obj, final List<OrgFieldEntity> orgFieldEntities) {
        T saasDTO = newInstance();
        orgFieldEntities.stream().forEach(orgFieldEntity -> {
            Method method = ReflectUtil.getMethod(obj.getClass(), "get", Object.class);
            if (null != method) {
                Object fieldValue = ReflectUtil.invokeWithCheck(obj, method, orgFieldEntity.getFieldName());
                ReflectUtils.INSTANCE.setFieldValue(saasDTO, orgFieldEntity.getSaasFieldName(), fieldValue);
            }
        });
        return saasDTO;
    }
    
    /**
     * newInstance.
     *
     * @return T
     */
    @SneakyThrows
    protected T newInstance() {
        Type genericSuperclass = getClass().getGenericSuperclass();
        ParameterizedType parameterizedType = null;
        if (genericSuperclass instanceof ParameterizedType) {
            parameterizedType = (ParameterizedType) genericSuperclass;
            Type[] typeArray = parameterizedType.getActualTypeArguments();
            if (typeArray != null && typeArray.length > 0) {
                Class<T> clazz = (Class<T>) typeArray[0];
                return clazz.getConstructor().newInstance();
            }
        }
        return null;
    }
    
}
